/*
 * Copyright (c) 2010-2011, The Bishops Arm Project All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.  Redistributions in binary
 * form must reproduce the above copyright notice, this list of conditions and
 * the following disclaimer in the documentation and/or other materials
 * provided with the distribution.  Neither the name of the The Bishops Arm
 * Project nor the names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package se.joinenea.bishopsarm;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import android.bluetooth.BluetoothSocket;
import android.util.Log;

/**
 * This class implements (part of) the NXT direct communication protocol
 * described in the NXT Bluetooth Development Kit
 *
 * The method to use is @see setMotorState.
 */
public class NXTBot {

    private static final String TAG = "BishopsArm.NXTBot";

    private final DataOutput output;
    private final DataInput input;

    private final PhoneOrientationHandler phoneOrientationHandler;
    private final NXTMotorController nxtMotorHandler;
    private final NXTColorSensorHandler nxtColorSensorHandler;

    public static NXTBot createBot(BluetoothSocket socket, BishopsArm activity)
            throws IOException {
        NXTBot nxtBot = new NXTBot(socket, activity);
        nxtBot.initColorSensor();
        return nxtBot;
    }

    private NXTBot(BluetoothSocket btSocket, BishopsArm activity)
            throws IOException {
        this.output = new DataOutputStream(btSocket.getOutputStream());
        this.input = new DataInputStream(btSocket.getInputStream());
        this.phoneOrientationHandler =
                new PhoneOrientationHandler(activity, this);
        this.nxtMotorHandler = new NXTMotorController(this);
        this.nxtColorSensorHandler = new NXTColorSensorHandler(this);
    }

    /*
     * public void playTone(int frequency, int duration) throws IOException {
     * Assert.range(frequency, 200, 14000); Assert.largerThan(duration, 200);
     *
     * ByteBuffer buffer = createBuffer(); buffer.put((byte) 0x80);
     * buffer.put((byte) 0x03); buffer.putShort((short) frequency);
     * buffer.putShort((short) duration); setSizeAndOutput(buffer); }
     */

    void setMotorState(int left, int right) throws IOException {
        nxtMotorHandler.setMotorState(left, right);
    }

    private void initColorSensor() throws IOException {
        nxtColorSensorHandler.initColorSensor();
    }

    public int getLightVal() throws IOException {
        return nxtColorSensorHandler.getLightVal();
    }

    public void stop() throws IOException {
        nxtMotorHandler.stop();
        phoneOrientationHandler.stop();
    }

    byte[] readPacket() throws IOException {
        Log.d(TAG, "Waiting for response...");
        byte[] lenArray = new byte[2];
        input.readFully(lenArray);
        short len =
                ByteBuffer.wrap(lenArray).order(ByteOrder.LITTLE_ENDIAN)
                        .getShort();
        byte[] response = new byte[len];
        input.readFully(response);
        Log.d(TAG, "Read packet with length=" + len);
        return response;
    }

    void sendMessage(ByteBuffer buffer) throws IOException {
        int packageSize = buffer.position() - 2;
        buffer.putShort(0, (short) (packageSize));

        buffer.flip();

        byte[] out = new byte[packageSize + 2];
        buffer.get(out);

        Log.d(TAG, StringUtils.toHex(out));

        output.write(out);
    }


    public void registerSensorListener() {
        phoneOrientationHandler.registerListener();
    }

    public void unregisterSensorListener() {
        phoneOrientationHandler.unregisterListener();
    }
}
